﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sern.Abstracts.Booster;
using Sern.Abstracts.Collector;
using Sern.Abstracts.Common;
using Sern.Abstracts.Feeder;
using Sern.Abstracts.Filter;
using Sern.Abstracts.Splitter;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Abstracts.Tracker.ServiceContracts;
using Sern.ServiceImplementation.MapReduce;

namespace Sern.ServiceImplementation
{
    public class ClientTypeToEnumMapper : Dictionary<Type, ClientType>, IClientTypeToEnumMapper
    {
        public ClientTypeToEnumMapper()
        {
            Add(typeof(IFeeder), ClientType.Feeder);
            Add(typeof(ISplitter<,>), ClientType.Splitter);
            Add(typeof(IFilter<,>), ClientType.Filter);
            Add(typeof (IBooster<,>), ClientType.Booster);
            Add(typeof(ICollector<,>), ClientType.Collector);
            Add(typeof(ITracker),ClientType.Tracker);
            Add(typeof(ITrackerHost), ClientType.TrackerHost);
            Add(typeof(ITrackerLogging), ClientType.TrackerLogging);
            Add(typeof(ITrackerMonitoringClient), ClientType.TrackerMonitor);
            Add(typeof(ITrackerTelemetryReceiver), ClientType.TrackerTelemetry);
            Add(typeof(IMapReduceHost), ClientType.MapReduceHost);
        }

        ClientType IClientTypeToEnumMapper.this[Type t]
        {
            get
            {

                if (t.IsGenericType && Keys.Any(k => k == t.GetGenericTypeDefinition()))
                    return base[t.GetGenericTypeDefinition()];
                else if (Keys.Any(k => k == t.GetGenericTypeDefinition()))
                    return base[t];
                else if (t.GetInterfaces().Where(i => i.IsGenericType).Select(i => i.IsGenericTypeDefinition ? i.GetGenericTypeDefinition() : i)
                    .Join(Keys, _ => _, _ => _, (_, __) => _).Any()
                    )
                    return
                        base[
                            t.GetInterfaces().Where(i => i.IsGenericType).Select(
                                i => i.IsGenericTypeDefinition ? i.GetGenericTypeDefinition() : i).Single()];
                else
                    throw new NotImplementedException("Unrecognized type");
            }
        }

        public Type this[ClientType clientType]
        {
            get
            {
                return this.ToArray().Where(_ => _.Value == clientType).Select(_ => _.Key).Single();
            }
        }
    }
}
